# MA策略
# 一、选择账号登录 MT5
# 二、选择交易品种，获取行情数据
# 三、获取数据
#   1.获取200 M1均线数据
#   2.获取20 M1均线数据
# 四、策略执行
#   1.判断200均线是否上穿20均线
#   2.判断200均线是否下穿20均线
#   3.设置仓位并建仓
#   4.设置止损、止盈、持续监控
# 五、平仓退出
#   1.判断是否持仓
#   2.满足条件平仓

import pandas as pd
import numpy as np
from datetime import datetime, timedelta
import MetaTrader5 as mt5
import time

# Strategy parameters
SYMBOL = "EURUSDm"
LOT = 0.01
STOP_LOSS_PIPS = 100
TAKE_PROFIT_PIPS = 200
TIMEFRAME = mt5.TIMEFRAME_D1
PERIOD = 200

def get_ma_crossover():
    """获取均线交叉信号"""
    rates = mt5.copy_rates_from_pos(SYMBOL, TIMEFRAME, 0, PERIOD)
    if rates is None or len(rates) < PERIOD:
        return None, None, None
    
    rates_frame = pd.DataFrame(rates)
    
    # Calculate moving averages
    ma_200 = rates_frame.iloc[:, 4].rolling(window=50).mean()
    ma_30 = rates_frame.iloc[:, 4].rolling(window=10).mean()
    
    # Get current and previous values
    current_ma_200 = ma_200.iloc[-1]
    previous_ma_200 = ma_200.iloc[-2]
    current_ma_30 = ma_30.iloc[-1]
    previous_ma_30 = ma_30.iloc[-2]
    
    # Detect crossover signals
    golden_cross = previous_ma_200 <= previous_ma_30 and current_ma_200 > current_ma_30
    death_cross = previous_ma_200 >= previous_ma_30 and current_ma_200 < current_ma_30
    
    current_price = rates_frame.iloc[-1, 4]  # Close price
    
    return golden_cross, death_cross, current_price

def calculate_pip_value(symbol):
    """计算点值"""
    symbol_info = mt5.symbol_info(symbol)
    if symbol_info is None:
        return 0.0001  # Default pip size
    return symbol_info.point


def calculate_average_of_moving_averages(symbol, ma_period=30, count=30):
    """
    计算指定数量移动平均线的平均值
    """
    # 获取足够数据
    rates = mt5.copy_rates_from_pos(symbol, mt5.TIMEFRAME_M1, 0, ma_period + count)
    
    if rates is None or len(rates) < ma_period:
        print(f"{symbol} 数据不足")
        return None
    
    # 提取收盘价
    close_prices = np.array([rate['close'] for rate in rates])
    
    # 计算移动平均线
    weights = np.ones(ma_period) / ma_period
    moving_averages = np.convolve(close_prices, weights, mode='valid')
    
    # 取指定数量的移动平均值并计算平均值
    selected_mas = moving_averages[:count]  # 取前count个
    avg_of_mas = np.mean(selected_mas)
    
    return avg_of_mas
def place_order(order_type, price):
    """下单函数"""
    symbol_info = mt5.symbol_info(SYMBOL)
    if symbol_info is None:
        print(f"Failed to get symbol info for {SYMBOL}")
        return None
        
    pip_value = calculate_pip_value(SYMBOL)
    
    # Calculate SL and TP
    if order_type == mt5.ORDER_TYPE_BUY:
        sl = price - STOP_LOSS_PIPS * pip_value
        tp = price + TAKE_PROFIT_PIPS * pip_value
        deviation = 20
        request = {
            "action": mt5.TRADE_ACTION_DEAL,
            "symbol": SYMBOL,
            "volume": LOT,
            "type": mt5.ORDER_TYPE_BUY,
            "price": price,
            # "sl": sl,
            # "tp": tp,
            "deviation": deviation,
            "magic": 234000,
            "comment": "MA Strategy",
            "type_time": mt5.ORDER_TIME_GTC,
            "type_filling": mt5.ORDER_FILLING_FOK,
        }
    elif order_type == mt5.ORDER_TYPE_SELL:
        sl = price + STOP_LOSS_PIPS * pip_value
        tp = price - TAKE_PROFIT_PIPS * pip_value
        deviation = 20
        request = {
            "action": mt5.TRADE_ACTION_DEAL,
            "symbol": SYMBOL,
            "volume": LOT,
            "type": mt5.ORDER_TYPE_SELL,
            "price": price,
            # "sl": sl,
            # "tp": tp,
            "deviation": deviation,
            "magic": 234000,
            "comment": "MA Strategy",
            "type_time": mt5.ORDER_TIME_GTC,
            "type_filling": mt5.ORDER_FILLING_FOK,
        }
    else:
        return None
    
    # Send order
    result = mt5.order_send(request)
    if result.retcode != mt5.TRADE_RETCODE_DONE:
        print(f"Order failed: {result.retcode}, {result.comment}")
        return None
    
    print(f"Order placed successfully: {order_type}, Price: {price}")
    return result

def close_all_positions():
    """平仓所有持仓"""
    positions = mt5.positions_get(symbol=SYMBOL)
    if positions is None or len(positions) == 0:
        return True
    
    for pos in positions:
        # Prepare closing request
        if pos.type == mt5.POSITION_TYPE_BUY:
            order_type = mt5.ORDER_TYPE_SELL
            price = mt5.symbol_info_tick(SYMBOL).bid
        else:
            order_type = mt5.ORDER_TYPE_BUY
            price = mt5.symbol_info_tick(SYMBOL).ask
            
        request = {
            "action": mt5.TRADE_ACTION_DEAL,
            "symbol": SYMBOL,
            "volume": pos.volume,
            "type": order_type,
            "position": pos.ticket,
            "price": price,
            "deviation": 20,
            "magic": 234000,
            "comment": "Close Position",
            "type_time": mt5.ORDER_TIME_GTC,
            "type_filling": mt5.ORDER_FILLING_IOC,
        }
        
        result = mt5.order_send(request)
        if result.retcode != mt5.TRADE_RETCODE_DONE:
            print(f"Failed to close position {pos.ticket}: {result.comment}")
            return False
            
    print("All positions closed")
    return True

def check_and_close_positions():
    """检查并根据条件平仓"""
    positions = mt5.positions_get(symbol=SYMBOL)
    if positions is None or len(positions) == 0:
        return
    
    # In this simple strategy, we let SL/TP handle exits
    # But we could add additional exit conditions here
    print(f"Currently holding {len(positions)} positions")

def main_strategy():
    """主策略逻辑"""
    print("开始执行均线交易策略")
    
    while True:
        try:
            # Check if we already have positions
            check_and_close_positions()
            
            # Get crossover signals
            golden_cross, death_cross, current_price = get_ma_crossover()
            
            if golden_cross is None:
                time.sleep(10)
                continue
                
            # Check if we already have positions before entering new ones
            positions = mt5.positions_get(symbol=SYMBOL)
            has_positions = positions is not None and len(positions) > 0
            
            # Execute strategy only if no positions exist
            if not has_positions:
                if golden_cross:
                    print("检测到金叉信号 - 准备做多")
                    price = mt5.symbol_info_tick(SYMBOL).ask
                    place_order(mt5.ORDER_TYPE_BUY, price)
                    
                elif death_cross:
                    print("检测到死叉信号 - 准备做空")
                    price = mt5.symbol_info_tick(SYMBOL).bid
                    place_order(mt5.ORDER_TYPE_SELL, price)
            
            # Print current status
            print(f"当前价格: {current_price}")
            if golden_cross:
                print("金叉信号")
            elif death_cross:
                print("死叉信号")
                
        except Exception as e:
            print(f"策略执行错误: {e}")
            
        # Wait before next iteration
        time.sleep(60)  # Check every minute

# Account login
ACCOUNT = 277203715
PWD = "WANGhou@1234"
SERVER = "Exness-MT5Trial5"

# Initialize MT5
if not mt5.initialize(login=ACCOUNT, password=PWD, server=SERVER):
    print("initialize() failed, error code =", mt5.last_error())
    quit()

# Login to account
authorized = mt5.login(ACCOUNT, password=PWD, server=SERVER)
if not authorized:
    print("Failed to login to account")
    quit()

print("成功连接到MT5账户")

# Run main strategy
try:
    main_strategy()
except KeyboardInterrupt:
    print("策略已停止")
finally:
    mt5.shutdown()